package info.batcloud.fanli.core.service.impl;

import com.ctospace.archit.common.pagination.Paging;
import com.taobao.api.TaobaoClient;
import info.batcloud.fanli.core.client.TaobaoUnionClient;
import info.batcloud.fanli.core.constants.TaobaoClientConstants;
import info.batcloud.fanli.core.entity.ItemSelection;
import info.batcloud.fanli.core.entity.Shopcat;
import info.batcloud.fanli.core.enums.EcomPlat;
import info.batcloud.fanli.core.enums.ItemSelectionStatus;
import info.batcloud.fanli.core.helper.PagingHelper;
import info.batcloud.fanli.core.item.collection.CollectResult;
import info.batcloud.fanli.core.item.collection.CommissionItemCollector;
import info.batcloud.fanli.core.item.collection.ItemSelectionCollectorDispatcher;
import info.batcloud.fanli.core.repository.ChannelRepository;
import info.batcloud.fanli.core.repository.ItemSelectionRepository;
import info.batcloud.fanli.core.repository.ShopcatRepository;
import info.batcloud.fanli.core.service.ItemSelectionService;
import info.batcloud.fanli.core.service.SystemSettingService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.inject.Inject;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ItemSelectionServiceImpl implements ItemSelectionService {

    private static final Logger logger = LoggerFactory.getLogger(ItemSelectionServiceImpl.class);

    @Inject
    private ItemSelectionRepository itemSelectionRepository;

    @Inject
    private ChannelRepository channelRepository;

    @Inject
    @Qualifier(TaobaoClientConstants.TAOBAO_CLIENT_ITEM_TBK)
    private TaobaoClient taobaoClient;

    @Inject
    private ItemSelectionCollectorDispatcher itemSelectionCollectorDispatcher;

    @Inject
    private TaobaoUnionClient taobaoUnionClient;

    @Inject
    private ShopcatRepository shopcatRepository;

    @Inject
    private SystemSettingService systemSettingService;

    @Override
    public ItemSelectionDto addItemSelection(ItemSelectionAddParam param) {
        ItemSelection selection = new ItemSelection();
        selection.setCreateTime(new Date());
        selection.setEcomPlat(EcomPlat.TAOBAO);
        selection.setName(param.getName());
        selection.setConfig(param.getConfig());
        selection.setStatus(param.getStatus());
        selection.setAutoFetch(param.isAutoFetch());
        selection.setMaxPage(param.getMaxPage());
        selection.setType(param.getType());
        selection.setRecommend(param.isRecommend());
        selection.setClearChannelItem(param.isClearChannelItem());
        if (param.getChannelId() != null) {
            selection.setChannel(channelRepository.findOne(param.getChannelId()));
        }
        if (param.getShopcatId() != null) {
            selection.setShopcat(shopcatRepository.findOne(param.getShopcatId()));
        }
        itemSelectionRepository.save(selection);
        return of(selection);
    }

    @Override
    public void updateItemSelection(long id, ItemSelectionUpdateParam param) {
        ItemSelection selection = itemSelectionRepository.findOne(id);
        selection.setCreateTime(new Date());
        selection.setEcomPlat(EcomPlat.TAOBAO);
        selection.setName(param.getName());
        selection.setConfig(param.getConfig());
        selection.setStatus(param.getStatus());
        selection.setAutoFetch(param.isAutoFetch());
        selection.setMaxPage(param.getMaxPage());
        selection.setType(param.getType());
        selection.setRecommend(param.isRecommend());
        selection.setClearChannelItem(param.isClearChannelItem());
        if (param.getChannelId() != null) {
            selection.setChannel(channelRepository.findOne(param.getChannelId()));
        }
        if (param.getShopcatId() != null) {
            selection.setShopcat(shopcatRepository.findOne(param.getShopcatId()));
        }
        itemSelectionRepository.save(selection);
    }

    @Override
    public Paging<ItemSelectionDto> search(SearchParam param) {
        Specification<ItemSelection> specification = (root, query, cb) -> {
            Predicate predicate = cb.conjunction();
            List<Expression<Boolean>> expressions = predicate.getExpressions();
            expressions.add(cb.notEqual(root.get("status"), ItemSelectionStatus.DELETED));
            if (StringUtils.isNotBlank(param.getName())) {
                expressions.add(cb.like(root.get("name"), "%" + param.getName() + "%"));
            }
            if (param.getChannelId() != null) {
                expressions.add(cb.equal(root.get("channel").get("id"), param.getChannelId()));
            }
            if (param.getShopcatId() != null) {
                Shopcat shopcat = shopcatRepository.findOne(param.getShopcatId());
                expressions.add(cb.like(root.get("shopcat").get("path"), shopcat.getPath() + "%"));
            }
            if (param.getType() != null) {
                expressions.add(cb.equal(root.get("type"), param.getType()));
            }
            if (param.getStatus() != null) {
                expressions.add(cb.equal(root.get("status"), param.getStatus()));
            }
            if (param.getRecommend() != null && param.getRecommend()) {
                expressions.add(cb.equal(root.get("recommend"), param.getRecommend()));
            }
            return predicate;
        };
        Sort sort = null;
        if (param.getSort() != null) {
            switch (param.getSort()) {
                case ID_DESC:
                    sort = new Sort(Sort.Direction.DESC, "id");
                    break;
                case FETCH_TIME_DESC:
                    sort = new Sort(Sort.Direction.DESC, "lastFetchTime");
                    break;
                default:
                    sort = new Sort(Sort.Direction.DESC, "id");
            }
        } else {
            sort = new Sort(Sort.Direction.DESC, "id");
        }
        Pageable pageable = new PageRequest(param.getPage() - 1,
                param.getPageSize(), sort);
        Page<ItemSelection> page = itemSelectionRepository.findAll(specification, pageable);
        return PagingHelper.of(page, o -> of(o), param.getPage(), param.getPageSize());
    }

    @Override
    public void setStatusById(long id, ItemSelectionStatus status) {
        ItemSelection selection = itemSelectionRepository.findOne(id);
        selection.setStatus(status);
        itemSelectionRepository.save(selection);
    }

    @Override
    public CollectResult collectByItemSelectionId(long itemSelectionId) {
        CollectResult result = itemSelectionCollectorDispatcher.collect(itemSelectionId, null);
        return result;
    }

    private List<ItemSelectionDto> of(List<ItemSelection> itemSelectionList) {
        return itemSelectionList.stream().map(c -> of(c)).collect(Collectors.toList());
    }

    private ItemSelectionDto of(ItemSelection itemSelection) {
        ItemSelectionDto dto = new ItemSelectionDto();
        BeanUtils.copyProperties(itemSelection, dto);
        if (itemSelection.getChannel() != null) {
            dto.setChannelId(itemSelection.getChannel().getId());
            dto.setChannelName(itemSelection.getChannel().getName());
        }
        if (itemSelection.getShopcat() != null) {
            dto.setShopcatId(itemSelection.getShopcat().getId());
            dto.setShopcatTitle(itemSelection.getShopcat().getTitle());
        }
        return dto;
    }
}
